"""
数据库优化器核心模块

实现数据库优化的主要功能，包括碎片整理、索引重建、数据清理和统计信息更新。
提供进度回调机制，支持错误处理和重试逻辑。
"""

import time
import sqlite3
from typing import List, Dict, Any, Optional, Callable
from .config import OptimizerConfig
from .utils import get_logger

# 获取日志记录器
logger = get_logger(__name__)


class OptimizationResult:
    """
    优化结果类
    
    存储数据库优化操作的执行结果，包括成功状态、执行步骤、错误信息等。
    提供友好的结果访问和格式化输出。
    """
    
    def __init__(self):
        """
        初始化优化结果对象
        """
        self.success: bool = False
        self.steps_completed: List[str] = []
        self.steps_failed: List[str] = []
        self.errors: List[str] = []
        self.warnings: List[str] = []
        self.start_time: float = 0.0
        self.end_time: float = 0.0
        self.tables_optimized: int = 0
    
    def start_timer(self):
        """
        开始计时
        """
        self.start_time = time.time()
    
    def stop_timer(self):
        """
        停止计时
        """
        self.end_time = time.time()
    
    def get_duration(self) -> float:
        """
        获取执行耗时（秒）
        
        Returns:
            执行时间（秒）
        """
        return self.end_time - self.start_time
    
    def add_success_step(self, step_name: str):
        """
        添加成功完成的步骤
        
        Args:
            step_name: 步骤名称
        """
        self.steps_completed.append(step_name)
    
    def add_failed_step(self, step_name: str):
        """
        添加失败的步骤
        
        Args:
            step_name: 步骤名称
        """
        self.steps_failed.append(step_name)
    
    def add_error(self, error_msg: str):
        """
        添加错误信息
        
        Args:
            error_msg: 错误信息
        """
        self.errors.append(error_msg)
    
    def add_warning(self, warning_msg: str):
        """
        添加警告信息
        
        Args:
            warning_msg: 警告信息
        """
        self.warnings.append(warning_msg)
    
    def to_dict(self) -> Dict[str, Any]:
        """
        将结果转换为字典格式
        
        Returns:
            包含结果信息的字典
        """
        return {
            'success': self.success,
            'duration': self.get_duration(),
            'steps_completed': self.steps_completed,
            'steps_failed': self.steps_failed,
            'errors': self.errors,
            'warnings': self.warnings,
            'tables_optimized': self.tables_optimized
        }
    
    def __str__(self) -> str:
        """
        格式化结果为字符串
        
        Returns:
            格式化的结果字符串
        """
        status = "成功" if self.success else "失败"
        duration = self.get_duration()
        
        result_str = f"优化结果: {status}\n"
        result_str += f"执行时间: {duration:.2f} 秒\n"
        result_str += f"完成步骤: {len(self.steps_completed)}\n"
        result_str += f"失败步骤: {len(self.steps_failed)}\n"
        result_str += f"优化表数: {self.tables_optimized}\n"
        
        if self.errors:
            result_str += "\n错误信息:\n"
            for error in self.errors:
                result_str += f"- {error}\n"
        
        if self.warnings:
            result_str += "\n警告信息:\n"
            for warning in self.warnings:
                result_str += f"- {warning}\n"
        
        return result_str


class DatabaseOptimizer:
    """
    数据库优化器类
    
    提供完整的数据库优化功能，包括碎片整理、索引重建、数据清理和统计信息更新。
    支持进度回调、错误处理和重试机制。
    """
    
    def __init__(self, config: Optional[OptimizerConfig] = None):
        """
        初始化数据库优化器
        
        Args:
            config: 优化器配置，如不提供则使用默认配置
        """
        self.config = config or OptimizerConfig.get_default_config()
        self._connection = None
        self._cursor = None
    
    def optimize(self, 
                connection: Optional[sqlite3.Connection] = None,
                progress_callback: Optional[Callable[[int, str], None]] = None
                ) -> OptimizationResult:
        """
        执行数据库优化操作
        
        Args:
            connection: SQLite数据库连接对象，如果为None则会自动获取连接
            progress_callback: 进度回调函数，接收进度百分比和状态消息
            
        Returns:
            优化结果对象
        """
        result = OptimizationResult()
        result.start_timer()
        
        try:
            # 处理连接
            self._setup_connection(connection)
            
            # 执行优化步骤
            current_progress = 0
            
            # 1. 执行VACUUM操作
            if self.config.get_option('enable_vacuum'):
                self._update_progress(progress_callback, current_progress, "准备执行VACUUM操作...")
                if self._execute_vacuum(result):
                    current_progress += self.config.get_step_weight('vacuum')
                    self._update_progress(progress_callback, current_progress, "VACUUM操作完成")
            else:
                logger.info("VACUUM操作已禁用")
            
            # 2. 重建索引
            if self.config.get_option('enable_reindex'):
                self._update_progress(progress_callback, current_progress, "开始重建索引...")
                tables_processed = self._rebuild_indexes(result)
                result.tables_optimized = tables_processed
                
                # 按表数量分配进度
                if tables_processed > 0:
                    reindex_weight = self.config.get_step_weight('reindex')
                    progress_increment = reindex_weight / tables_processed
                    current_progress += reindex_weight
                    
                self._update_progress(progress_callback, current_progress, f"索引重建完成，共处理 {tables_processed} 个表")
            else:
                logger.info("索引重建已禁用")
            
            # 3. 清理冗余数据
            if self.config.get_option('enable_cleanup'):
                self._update_progress(progress_callback, current_progress, "执行冗余数据清理...")
                if self._cleanup_redundant_data(result):
                    current_progress += self.config.get_step_weight('cleanup')
                    self._update_progress(progress_callback, current_progress, "数据清理完成")
            else:
                logger.info("数据清理已禁用")
            
            # 4. 更新统计信息
            if self.config.get_option('enable_analyze'):
                self._update_progress(progress_callback, current_progress, "更新数据库统计信息...")
                if self._execute_analyze(result):
                    current_progress += self.config.get_step_weight('analyze')
            
            # 确保进度达到100%
            self._update_progress(progress_callback, 100, "数据库优化完成")
            
            # 如果没有失败的步骤，则优化成功
            result.success = len(result.steps_failed) == 0
            
        except Exception as e:
            error_msg = f"优化过程发生异常: {str(e)}"
            logger.error(error_msg)
            result.add_error(error_msg)
            result.add_failed_step("优化主流程")
            self._update_progress(progress_callback, -1, f"错误: {str(e)}")
        finally:
            # 清理资源
            self._cleanup_resources()
            result.stop_timer()
        
        return result
    
    def _setup_connection(self, connection: Optional[sqlite3.Connection]) -> None:
        """
        设置数据库连接
        
        Args:
            connection: 外部提供的数据库连接
        """
        if connection:
            self._connection = connection
            self._cursor = connection.cursor()
            logger.info("使用外部提供的数据库连接")
        else:
            # 如果没有提供连接，尝试从db_utils获取
            try:
                from db_utils import DatabaseUtils
                self._connection = DatabaseUtils.get_connection()
                self._cursor = self._connection.cursor()
                logger.info("从DatabaseUtils获取数据库连接")
            except ImportError:
                raise ImportError("未提供连接且无法导入db_utils模块")
    
    def _cleanup_resources(self) -> None:
        """
        清理资源，关闭游标和连接（如果是内部创建的）
        """
        try:
            if self._cursor:
                self._cursor.close()
                self._cursor = None
        except Exception as e:
            logger.warning(f"关闭游标时出错: {str(e)}")
        
        # 注意：不关闭外部提供的连接，由调用者负责
        self._connection = None
    
    def _execute_vacuum(self, result: OptimizationResult) -> bool:
        """
        执行VACUUM命令进行碎片整理
        
        Args:
            result: 结果对象，用于记录执行状态
            
        Returns:
            是否成功执行
        """
        step_name = "VACUUM碎片整理"
        logger.info("开始执行VACUUM命令进行数据库碎片整理")
        
        try:
            self._cursor.execute("VACUUM")
            result.add_success_step(step_name)
            logger.info("VACUUM命令执行成功")
            return True
        except Exception as e:
            error_msg = f"执行VACUUM失败: {str(e)}"
            logger.error(error_msg)
            result.add_error(error_msg)
            result.add_failed_step(step_name)
            return False
    
    def _rebuild_indexes(self, result: OptimizationResult) -> int:
        """
        重建所有表的索引
        
        Args:
            result: 结果对象，用于记录执行状态
            
        Returns:
            处理的表数量
        """
        step_name = "索引重建"
        tables_processed = 0
        logger.info("开始重建数据库索引")
        
        try:
            # 获取所有表名
            query = "SELECT name FROM sqlite_master WHERE type='table'"
            
            # 如果配置为排除系统表，则添加过滤条件
            if self.config.get_option('exclude_system_tables'):
                query += " AND name NOT LIKE 'sqlite_%'"
            
            self._cursor.execute(query)
            tables = self._cursor.fetchall()
            
            # 为每个表重建索引
            for table in tables:
                table_name = table[0]
                try:
                    logger.info(f"重建表 {table_name} 的索引")
                    self._cursor.execute(f"REINDEX '{table_name}';")
                    tables_processed += 1
                except Exception as e:
                    warning_msg = f"重建表 {table_name} 的索引失败: {str(e)}"
                    logger.warning(warning_msg)
                    result.add_warning(warning_msg)
            
            if tables_processed > 0:
                result.add_success_step(step_name)
                logger.info(f"索引重建完成，共处理 {tables_processed} 个表")
            else:
                warning_msg = "未找到需要重建索引的表"
                logger.warning(warning_msg)
                result.add_warning(warning_msg)
                
        except Exception as e:
            error_msg = f"获取表列表时出错: {str(e)}"
            logger.error(error_msg)
            result.add_error(error_msg)
            result.add_failed_step(step_name)
        
        return tables_processed
    
    def _cleanup_redundant_data(self, result: OptimizationResult) -> bool:
        """
        清理冗余数据
        
        Args:
            result: 结果对象，用于记录执行状态
            
        Returns:
            是否成功执行
        """
        step_name = "冗余数据清理"
        logger.info("执行冗余数据清理")
        
        try:
            # 这里可以根据实际需求添加具体的清理逻辑
            # 例如删除临时表、清理无效记录等
            # 当前实现为基础框架，可根据具体业务需求扩展
            
            result.add_success_step(step_name)
            logger.info("冗余数据清理完成")
            return True
        except Exception as e:
            error_msg = f"执行数据清理失败: {str(e)}"
            logger.error(error_msg)
            result.add_error(error_msg)
            result.add_failed_step(step_name)
            return False
    
    def _execute_analyze(self, result: OptimizationResult) -> bool:
        """
        执行ANALYZE命令更新统计信息
        
        Args:
            result: 结果对象，用于记录执行状态
            
        Returns:
            是否成功执行
        """
        step_name = "统计信息更新"
        logger.info("执行ANALYZE更新统计信息")
        
        try:
            self._cursor.execute("ANALYZE")
            result.add_success_step(step_name)
            logger.info("ANALYZE命令执行成功")
            return True
        except Exception as e:
            error_msg = f"执行ANALYZE失败: {str(e)}"
            logger.error(error_msg)
            result.add_error(error_msg)
            result.add_failed_step(step_name)
            return False
    
    def _update_progress(self, 
                        callback: Optional[Callable[[int, str], None]],
                        progress: int,
                        message: str
                        ) -> None:
        """
        更新进度
        
        Args:
            callback: 进度回调函数
            progress: 进度百分比
            message: 状态消息
        """
        if callback:
            try:
                callback(progress, message)
            except Exception as e:
                logger.warning(f"更新进度时出错: {str(e)}")
    
    def validate_connection(self, connection: Optional[sqlite3.Connection] = None) -> bool:
        """
        验证数据库连接是否有效
        
        Args:
            connection: 要验证的数据库连接
            
        Returns:
            连接是否有效
        """
        test_conn = connection or self._connection
        
        if not test_conn:
            return False
        
        try:
            cursor = test_conn.cursor()
            cursor.execute("SELECT 1")
            cursor.close()
            return True
        except Exception:
            return False